﻿
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mime;
using System.Threading.Tasks;
using NetMicro.Core.ApiFunction;
using NetMicro.Core.Extensions;
using NetMicro.Core.Helper;
using NetMicro.Validations.Attributes;
using NetMicro.Validations.Internal;

namespace NetMicro.Validations.Filters
{
    /// <summary>
    /// 数据验证过滤器
    /// </summary>

    public sealed class DataValidationFilter : IActionFilter
    {
        /// <summary>
        /// 动作方法执行之前操作
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            var method = actionDescriptor.MethodInfo;
            var modelState = context.ModelState;
            // 跳过验证类型
            var nonValidationAttributeType = typeof(NonValidationAttribute);

            // 如果贴了 [NonValidation] 特性 或 所在类型贴了 [NonValidation] 特性，则跳过验证
            if (actionDescriptor.Parameters.Count == 0 ||
                method.IsDefined(nonValidationAttributeType, true) ||
                method.ReflectedType.IsDefined(nonValidationAttributeType, true) || modelState.IsValid)
            {
                return;
            }
            // 返回验证失败结果
            if (context.Result == null && !modelState.IsValid)
            {
                // 设置验证失败结果
                SetValidateFailedResult(context, modelState);
            }
        }

        /// <summary>
        /// 设置验证失败结果
        /// </summary>
        /// <param name="context">动作方法执行上下文</param>
        /// <param name="modelState">模型验证状态</param>
        private static void SetValidateFailedResult(ActionExecutingContext context, ModelStateDictionary modelState)
        {
            List<string> errors = modelState
                   .Where(e => e.Value.Errors.Count > 0)
                   .Select(e => e.Value.Errors.First().ErrorMessage)
                   .ToList();
            string str = string.Join(";", errors);
            context.Result = new OkObjectResult(ServiceResult.Faild(StatusCodes.Status400BadRequest, str));
        }

        /// <summary>
        /// 动作方法执行完成操作
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
        }
    }
}